package com.itheima.d6_tcp3;

import java.io.DataInputStream;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

/**
 *  目标：完成TCP通信快速入门-服务端开发：要求实现与多个客户端同时通信。
 */
public class Server {
    public static void main(String[] args) throws Exception {
        System.out.println("-----服务端启动成功-------");
        // 1、创建ServerSocket的对象，同时为服务端注册端口。
        ServerSocket serverSocket = new ServerSocket(8888);

/*

        //尝试在服务端加个死循环，能否建立多个socket管道进行与客户端连接，测试能否满足服务端接收多个客户端的通信
        //结果：不能，这个大的死循环根本无法执行，因为一直在等待第一个连接的客户端的消息。所以还是只能接受一个客户端的连接
        while (true) {
            // 2、使用serverSocket对象，调用一个accept方法，等待客户端的连接请求
            Socket socket = serverSocket.accept();

            // 3、从socket通信管道中得到一个字节输入流。
            InputStream is = socket.getInputStream();

            // 4、把原始的字节输入流包装成数据输入流
            DataInputStream dis = new DataInputStream(is);

            while (true) {
                try {
                    // 5、使用数据输入流读取客户端发送过来的消息
                    String rs = dis.readUTF();
                    System.out.println(rs);
                } catch (Exception e) {
                    //拿到客户端的IP地址说离线了
                    System.out.println(socket.getRemoteSocketAddress() + "离线了！");
                    dis.close();
                    socket.close();
                    break;
                }
            }
        }
*/
    /*
    分析为什么之前udp协议是可以的：
    弹幕:因为UDP不需要连接，只要服务端程序端口开，有网就行。UDP是面向无连接的。udp接受的数据包，它接受的是对象不一样的
        而 TCP 需要为每个连接维护独立的会话，每个客户端连接到服务端时，服务端会为每个连接创建一个新的 Socket 对象，这些 Socket 对象之间是独立的

    为什么现在tcp协议时，不能与多个客户端连接：
    因为目前服务端只有一个线程与客户端进行连接
     */

        /*
        把上面的代码改造一下:
        1.socket通信管道交给一个独立的线程来执行
        2.主线程只负责接收新的客户端连接，而不应该像之前一样让主线程再去读这个管道里面的数据

        总结：现在服务端启动之后，主线程负责接收客户端连接，然后创建socket通信管道，然后把socket交给另一个独立的线程
             线程启动后，就会不断地从第一个客户端中接收信息
             接着这个死循环会继续执行，来等待第二个客户端通信管道的建立

        弹幕：TCP不是端到端吗，为什么8888这个端口可以同时让这么多客户端通信
             前面的，8888是服务端的端口，客户端在创建的时候会随机一个端口号
             线程安全的前提是修改了多线程间的共享资源，这里没修改共享资源怎么有线程安全问题

         */
        while (true) {
            //主线程只负责接受新的客户端连接
            // 2、使用serverSocket对象，调用一个accept方法，等待客户端的连接请求
            Socket socket = serverSocket.accept();

            //拓展：追踪客户端上线和下线。客户端上线都要经历--主线程把客户端管道接进来，所以接一个客户端管道，相当于知道了一个客户端上线了
            //通过getRemoteSocketAddress通信管道拿到客户端的IP地址
            System.out.println("有人上线了：" + socket.getRemoteSocketAddress());

            // 3、把这个客户端对应的socket通信管道，交给一个独立的线程负责处理。
            //让这个线程去处理当前这个客户端的socket通信管道，与其进行通信，所以要把这个socket通信管道交给这个线程。
            // 怎么交给他呢：有参构造器
            new ServerReaderThread(socket).start();
        }
    }
}













